<?php

abstract class _F_OBJECT_ {
	
	public $_f_this_;
	public $_f_object_properties_ = array();
	public $_f_object_methods_ = array();

	public function __set($name,$value) {
		$fn = '_f_set_'.$name.'_';
		if ($this->has_method($fn)) $this->$fn($value);
		else $this->_f_object_properties_[$name] = $value;
	}

	public function & __get($name) {
		$fn = '_f_get_'.$name.'_';
		if ($this->has_method($fn)) {
			$value = $this->$fn();
			return $value;
		}
		if (isset($this->_f_object_properties_[$name]))
			return $this->_f_object_properties_[$name];
		$backtrace = debug_backtrace();
		$lc = $backtrace[0];
		$cn = get_class($this);
		$msg = "VerSimF Notice: Undefined dynamic property: {$cn}::{$name}";
		if (isset($lc['file'])) {
			$msg .= " in {$lc['file']} on line {$lc['line']}";
		} else if (isset($lc['class'])) {
			$msg .= " in function {$lc['class']}::{$lc['function']}";
		} else if (isset($lc['function'])) {
			$msg .= " in function {$lc['function']}";
		}
		error_log($msg);
	}

	public function __isset($name) {
		$fn = '_f_isset_'.$name.'_';
		if ($this->has_method($fn)) return $this->$fn();
		$fn = '_f_get_'.$name.'_';
		if ($this->has_method($fn)) {
			$value = $this->$fn();
			return isset($value);
		}
		return isset($this->_f_object_properties_[$name]);
	}

	public function __unset($name) {
		$fn = '_f_unset_'.$name.'_';
		if ($this->has_method($fn)) {
			$this->$fn();
		} else {
			$fn = '_f_set_'.$name.'_';
			if ($this->has_method($fn)) {
				$this->$fn(null);
			} else {
				unset($this->_f_object_properties_[$name]);
			}
		}
	}
	
	public function register_method($name,$callback) {
		$prev_method = null;
		if (isset($this->_f_object_methods_[$name])) 
			$prev_method = $this->_f_object_methods_[$name];
		$this->_f_object_methods_[$name] = $callback;
		return $prev_method;
	}

	public function unregister_method($name,$callback) {
		unset($this->_f_object_methods_[$name]);
	}

	public function has_method($name) {
		return method_exists($this,$name) || 
			isset($this->_f_object_methods_[$name]);
	}

	public function __call($name,$arguments) {
		if (isset($this->_f_object_methods_[$name])) {
			$m = $this->_f_object_methods_[$name];
			if (is_array($m) && property_exists($m[0],'_f_this_')) 
				$m[0]->_f_this_ = $this;
			return call_user_func_array($m,$arguments);
		}
		$backtrace = debug_backtrace();
		$lc = $backtrace[1];
		$cn = get_class($this);
		$msg = "VerSimF Notice: Call to undefined dynamic method: {$cn}::{$name}";
		if (isset($lc['file'])) {
			$msg .= " in {$lc['file']} on line {$lc['line']}";
		} else if (isset($lc['class'])) {
			$msg .= " in function {$lc['class']}::{$lc['function']}";
		} else if (isset($lc['function'])) {
			$msg .= " in function {$lc['function']}";
		}
		error_log($msg);
	}

	public function put_properties($src) {
		if (isset($src)) {
			$src = is_object($src) ? get_object_vars($src) : $src;
			foreach ($src as $key => $val) $this->$key = $val;
		}
	}

}
